import functools
import random

from PIL import Image

# 装饰器
def now():
    print("2017-08-16")
f = now
print(f.__name__, now.__name__) # now now

# 这里的log就是装饰函数
def log(func):
    def wrapper(*args, **kw):
        print("before call %s()" % func.__name__)
        return func(*args, **kw)
    return wrapper

# 把@log放到now()函数的定义处，相当于执行了语句：now = log(now)
@log
def now():
    print("2017-08-25")
now() # call now() 2017-08-25

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

@log("liuling")
def now():
    print("2017-08-25")
now() # liuling now(): 2017-08-25

# 偏函数:当函数的参数个数太多，需要简化时，使用functools.partial可以创建一个新的函数，这个新函数可以固定住原函数的部分参数，从而在调用时更简单
print(int("123", base=16)) # 291
int16 = functools.partial(int, base=16)
print(int16("123")) # 291
print(int16("123", base=8)) # 83


# 第三方模块
im = Image.open("../file/seach_button.png")
print(im.format, im.size, im.mode) # PNG (25, 25) RGBA
im.thumbnail((10, 10))
im.save("../file/huhx.png", "PNG")


# class类：普通的函数相比，在类中定义的函数只有一点不同，就是第一个参数永远是实例变量self，并且，调用时，不用传递该参数。
class Student(object):
    def __init__(self, name, score):
        self.__name = name
        self.score = score
    def print_score(self):
        print("%s %s" % (self.__name, self.score))
huhx = Student("huhx", 90)
# print(huhx.__name, huhx.score) # 这里的__name不能直接访问，它是私有变量
liuling = Student("liuling", 100)
huhx.print_score() # huhx 90
liuling.print_score() # liuling 100

# 继承
class Man(Student):
    def __init__(self, name, score, age):
        self.name = name
        self.score = score
        self.age = age;
    def print_age(self):
        print(self.name, self.score, self.age)
man = Man("chenhui", 90, 23)
man.print_age() # chenhui 90 23

# 判断对象类型，使用type()函数：
print(type(man), type("123"), type(123)) # <class '__main__.Man'> <class 'str'> <class 'int'>
print(isinstance(man, Man), isinstance("123", str), isinstance(123, str)) # True True False
# 如果要获得一个对象的所有属性和方法，可以使用dir()函数
print(dir(man)) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'print_age', 'print_score', 'score']

# 实例属性和类属性
class Student(object):
   name = "huhx"
student = Student()
Student.name = "liuling"
print(student.name, Student.name) # liuling liuling
student.name = "chenhui"
print(student.name, Student.name) # chenhui liuling

# Python允许在定义class的时候，定义一个特殊的__slots__变量，来限制该class实例能添加的属性：
class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
s = Student()
# s.addr = "hubai"  AttributeError: 'Student' object has no attribute 'addr'

# @property的使用
class Student(object):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError("score must be an Integer")
        if value < 0 or value > 100:
            raise ValueError("score must between 0-100")
        self._score = value
s = Student()
s.score = 80
# s.score = 101

# 多重继承,__str__是类似于java中对象的toString方法。只需要定义一个__call__()方法，就可以直接对实例进行调用
class Human(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return "my name is %s" % self.name
    def __iter__(self):
        return self
    def __next__(self):
        return self.name + "" + str(random.random())
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a
    def __getattr__(self, item):
        if item == "score":
            return 99
    def __call__(self, *args, **kwargs):
        print("call method %s" % self.name)
human = Human("huhx")
print(human) # my name is huhx
# for item in human:
#     print(item)
print(human.score) # 99
human() # call method huhx








